/**
 * 请求拦截器
 * 官网文档：https://uview-plus.jiangruyi.com/js/http.html
 * @Author: liruilin 1443254530@qq.com
 * @Date: 2025-4-8 14:02:26
 * @LastEditors: liruilin 1443254530@qq.com
 * @FilePath: libs\common\request.js
 */

import { http, toast } from '@/uni_modules/uview-plus'
import { hasLoginTask } from '@/libs/hooks/user.js'
import { useUserStore } from '@/libs/store'
import $func from '@/libs/utils/index.js'

const install = (app) => {
    /**
     * 设置全局默认config
     */
    http.setConfig((config) => {
        const definConfig = {
            baseURL: uni.$mp.config.baseUrl, // 服务器地址
            header: {},
            // method: 'GET',
            dataType: 'json',
            // #ifndef MP-ALIPAY
            responseType: 'text',
            // #endif
            // 注：如果局部custom与全局custom有同名属性，则后面的属性会覆盖前面的属性，相当于Object.assign(全局，局部)
            // 全局自定义参数默认值
            custom: {
                // 接口是否需要验证登录
                auth: false,
                // 显示loading
                loading: false,
                // 是否需要自定义处理未登录逻辑，设置为true后拦截器将不会处理未登录逻辑，页面自行处理
                customLoginLogic: false
            }, 
            // #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
            timeout: 60000,
            // #endif
            // #ifdef APP-PLUS
            sslVerify: true,
            // #endif
            // #ifdef H5
            // 跨域请求时是否携带凭证（cookies）仅H5支持（HBuilderX 2.6.15+）
            withCredentials: false,
            // #endif
            // #ifdef APP-PLUS
            firstIpv4: false, // DNS解析时优先使用ipv4 仅 App-Android 支持 (HBuilderX 2.8.0+)
            // #endif
            // 局部优先级高于全局，返回当前请求的task,options。请勿在此处修改options。非必填
            // getTask: (task, options) => {
            // 相当于设置了请求超时时间500ms
            //   setTimeout(() => {
            //     task.abort()
            //   }, 500)
            // },
            // 全局自定义验证器。参数为statusCode 且必存在，不用判断空情况。
            validateStatus: (statusCode) => { // statusCode 必存在。此处示例为全局默认配置
                return statusCode >= 200 && statusCode < 300
            }
        }
        // return { ...config, ...definConfig }
        return $func.deepMerge(config, definConfig)
    })

    /**
     * 请求拦截
     * @param {Object} http
     */
    http.interceptors.request.use((config) => { // 可使用async await 做异步操作
        const userStore = useUserStore()
        // 初始化请求拦截器时，会执行此方法，此时data为undefined，赋予默认{}
        config.data = config.data || {}
        if (config.custom.auth) {
            if(userStore.isLogin){
                config.header.token = 'Authorization ' + userStore.token
            }else {
                return Promise.reject({
                    config,
                    errMsg: 'Not Logged In',
                    statusCode: 200,
                    data: {
                        // 这里的字段需要与服务端对接,这里的code是前端自定义code，用于判断是不是登录过期还是未登录
                        code: 301,
                        msg: 'Not Logged In'
                    }
                })
            }
        }

        if (config.custom.loading) {
            uni.$mp.loading.show()
        }
        
        return config
    }, (config) => {// 可使用async await 做异步操作
        Promise.reject(config)
    })

    /**
     * 响应拦截
     * @param {Object} http 
     */
    http.interceptors.response.use((response) => { /* 对响应成功做点什么 可使用async await 做异步操作*/
        // 自定义参数
        const custom = response.config?.custom
        
        if(custom.loading) uni.$mp.loading.hide()
        // 有data说明接口请求是成功的，需要处理业务错误逻辑
        if(response.statusCode === 200 && response.data){
            switch(response.data.code){
                // 成功
                case 0: 
                    return Promise.resolve(response.data)
                break
                // token失效 需要重新登录
                case 300:
                    if(!custom.customLoginLogic){
                        hasLoginTask(_ => null, '您需要登录后才能继续操作')
                    }
                    return Promise.reject(response.data)
                break
                default:
                    return Promise.reject(response.data)
            }
        }else {
            // 程序上或者网络上的错误直接返回请求错误，或者判断是不是网络出故障提醒用户之类的
            uni.showToast({
                title: '网络似乎开了点小差~~',
                icon: 'error',
                duration: 3000
            })
            return Promise.reject({ code: 404, msg: '请求出错' })
        }
    }, (response) => { /*  对响应错误处理 （statusCode !== 200）*/
        if(response.config.custom?.toast){
            toast(response.data.msg)
        }
        return Promise.reject(response)
    })

}

export default { install }